/*
 * @ : Copyright (c) 2021 Phytium Information Technology, Inc. 
 *  
 * SPDX-License-Identifier: Apache-2.0.
 * 
 * @Date: 2021-06-22 13:21:45
 * @LastEditTime: 2021-06-23 13:17:31
 * @Description:  This files is for 
 * 
 * @Modify History: 
 *  Ver   Who        Date         Changes
 * ----- ------     --------    --------------------------------------
 */

#ifndef _BSP_DRIVERS_GIC_AARCH32_GICV3_H
#define _BSP_DRIVERS_GIC_AARCH32_GICV3_H

#ifdef __cplusplus
extern "C"
{
#endif

/* For AArch32 state, 
   accesses to GIC registers that are visible in the System register */
#define __get_gicv3_reg(CR, Rt) __asm__ volatile("MRC " CR  \
                                                 : "=r"(Rt) \
                                                 :          \
                                                 : "memory")
#define __set_gicv3_reg(CR, Rt) __asm__ volatile("MCR " CR \
                                                 :         \
                                                 : "r"(Rt) \
                                                 : "memory")

/* AArch32 System register interface to GICv3 */
/* Group 0, reads this register to obtain the INTID, acts as 
an acknowledge for the interrupt */
#define ICC_IAR0 "p15, 0, %0, c12, c8, 0"
/* Group 1 */
#define ICC_IAR1 "p15, 0, %0, c12, c12, 0"
/* writes to this register to inform the CPU interface 
that it has completed the processing */
#define ICC_EOIR0 "p15, 0, %0, c12, c8, 1"
#define ICC_EOIR1 "p15, 0, %0, c12, c12, 1"
/*  GET the INTID of highest priority pending interrupt */
#define ICC_HPPIR0 "p15, 0, %0, c12, c8, 2"
#define ICC_HPPIR1 "p15, 0, %0, c12, c12, 2"
#define ICC_BPR0 "p15, 0, %0, c12, c8, 3"
#define ICC_BPR1 "p15, 0, %0, c12, c12, 3"
#define ICC_DIR "p15, 0, %0, c12, c11, 1"
#define ICC_PMR "p15, 0, %0, c4, c6, 0"
#define ICC_RPR "p15, 0, %0, c12, c11, 3"
#define ICC_CTLR "p15, 0, %0, c12, c12, 4"
#define ICC_MCTLR "p15, 6, %0, c12, c12, 4"
#define ICC_SRE "p15, 0, %0, c12, c12, 5"
#define ICC_HSRE "p15, 4, %0, c12, c9, 5"
#define ICC_MSRE "p15, 6, %0, c12, c12, 5"
#define ICC_IGRPEN0 "p15, 0, %0, c12, c12, 6"
#define ICC_IGRPEN1 "p15, 0, %0, c12, c12, 7"
#define ICC_MGRPEN1 "p15, 6, %0, c12, c12, 7"

#define __REG32(x) (*((volatile unsigned int *)((u32)x)))

#define ROUTED_TO_ALL (1)
#define ROUTED_TO_SPEC (0)

/** Macro to access the Distributor Control Register (GICD_CTLR)
*/
#define GICD_CTLR_RWP (1 << 31)
#define GICD_CTLR_E1NWF (1 << 7)
#define GICD_CTLR_DS (1 << 6)
#define GICD_CTLR_ARE_NS (1 << 5)
#define GICD_CTLR_ARE_S (1 << 4)
#define GICD_CTLR_ENGRP1S (1 << 2)
#define GICD_CTLR_ENGRP1NS (1 << 1)
#define GICD_CTLR_ENGRP0 (1 << 0)

/** Macro to access the Redistributor Control Register (GICR_CTLR)
*/
#define GICR_CTLR_UWP (1 << 31)
#define GICR_CTLR_DPG1S (1 << 26)
#define GICR_CTLR_DPG1NS (1 << 25)
#define GICR_CTLR_DPG0 (1 << 24)
#define GICR_CTLR_RWP (1 << 3)
#define GICR_CTLR_IR (1 << 2)
#define GICR_CTLR_CES (1 << 1)
#define GICR_CTLR_EnableLPI (1 << 0)

/** Macro to access the Generic Interrupt Controller Interface (GICC)
*/
#define GIC_CPU_CTRL(hw_base) __REG32((hw_base) + 0x00U)
#define GIC_CPU_PRIMASK(hw_base) __REG32((hw_base) + 0x04U)
#define GIC_CPU_BINPOINT(hw_base) __REG32((hw_base) + 0x08U)
#define GIC_CPU_INTACK(hw_base) __REG32((hw_base) + 0x0cU)
#define GIC_CPU_EOI(hw_base) __REG32((hw_base) + 0x10U)
#define GIC_CPU_RUNNINGPRI(hw_base) __REG32((hw_base) + 0x14U)
#define GIC_CPU_HIGHPRI(hw_base) __REG32((hw_base) + 0x18U)
#define GIC_CPU_IIDR(hw_base) __REG32((hw_base) + 0xFCU)

/** Macro to access the Generic Interrupt Controller Distributor (GICD)
*/
#define GIC_DIST_CTRL(hw_base) __REG32((hw_base) + 0x000U)
#define GIC_DIST_TYPE(hw_base) __REG32((hw_base) + 0x004U)
#define GIC_DIST_IGROUP(hw_base, n) __REG32((hw_base) + 0x080U + ((n) / 32U) * 4U)
#define GIC_DIST_ENABLE_SET(hw_base, n) __REG32((hw_base) + 0x100U + ((n) / 32U) * 4U)
#define GIC_DIST_ENABLE_CLEAR(hw_base, n) __REG32((hw_base) + 0x180U + ((n) / 32U) * 4U)
#define GIC_DIST_PENDING_SET(hw_base, n) __REG32((hw_base) + 0x200U + ((n) / 32U) * 4U)
#define GIC_DIST_PENDING_CLEAR(hw_base, n) __REG32((hw_base) + 0x280U + ((n) / 32U) * 4U)
#define GIC_DIST_ACTIVE_SET(hw_base, n) __REG32((hw_base) + 0x300U + ((n) / 32U) * 4U)
#define GIC_DIST_ACTIVE_CLEAR(hw_base, n) __REG32((hw_base) + 0x380U + ((n) / 32U) * 4U)
#define GIC_DIST_PRI(hw_base, n) __REG32((hw_base) + 0x400U + ((n) / 4U) * 4U)
#define GIC_DIST_TARGET(hw_base, n) __REG32((hw_base) + 0x800U + ((n) / 4U) * 4U)
#define GIC_DIST_CONFIG(hw_base, n) __REG32((hw_base) + 0xc00U + ((n) / 16U) * 4U)
#define GIC_DIST_SOFTINT(hw_base) __REG32((hw_base) + 0xf00U)
#define GIC_DIST_CPENDSGI(hw_base, n) __REG32((hw_base) + 0xf10U + ((n) / 4U) * 4U)
#define GIC_DIST_SPENDSGI(hw_base, n) __REG32((hw_base) + 0xf20U + ((n) / 4U) * 4U)
#define GIC_DIST_ICPIDR2(hw_base) __REG32((hw_base) + 0xfe8U)
#define GIC_DIST_IROUTER_LOW(hw_base, n) __REG32((hw_base) + 0x6000U + (n)*8U)
#define GIC_DIST_IROUTER_HIGH(hw_base, n) __REG32((hw_base) + 0x6000U + (n)*8U + 4)

/* SGI base address  is at 64K offset from Redistributor base address */
#define GIC_RSGI_OFFSET 0x10000

/** Macro to access the Generic Interrupt Controller Redistributor (GICD)
*/
#define GIC_RDIST_CTRL(hw_base) __REG32((hw_base) + 0x000U)
#define GIC_RDIST_IIDR(hw_base) __REG32((hw_base) + 0x004U)
#define GIC_RDIST_TYPER(hw_base) __REG32((hw_base) + 0x008U)
#define GIC_RDIST_TSTATUSR(hw_base) __REG32((hw_base) + 0x010U)
#define GIC_RDIST_WAKER(hw_base) __REG32((hw_base) + 0x014U)
#define GIC_RDIST_SETLPIR(hw_base) __REG32((hw_base) + 0x040U)
#define GIC_RDIST_CLRLPIR(hw_base) __REG32((hw_base) + 0x048U)
#define GIC_RDIST_PROPBASER(hw_base) __REG32((hw_base) + 0x070U)
#define GIC_RDIST_PENDBASER(hw_base) __REG32((hw_base) + 0x078U)
#define GIC_RDIST_INVLPIR(hw_base) __REG32((hw_base) + 0x0A0U)
#define GIC_RDIST_INVALLR(hw_base) __REG32((hw_base) + 0x0B0U)
#define GIC_RDIST_SYNCR(hw_base) __REG32((hw_base) + 0x0C0U)

#define GIC_RDISTSGI_IGROUPR0(hw_base, n) __REG32((hw_base) + GIC_RSGI_OFFSET + 0x080U + (n)*4U)
#define GIC_RDISTSGI_ISENABLER0(hw_base) __REG32((hw_base) + GIC_RSGI_OFFSET + 0x100U)
#define GIC_RDISTSGI_ICENABLER0(hw_base) __REG32((hw_base) + GIC_RSGI_OFFSET + 0x180U)
#define GIC_RDISTSGI_ISPENDR0(hw_base) __REG32((hw_base) + GIC_RSGI_OFFSET + 0x200U)
#define GIC_RDISTSGI_ICPENDR0(hw_base) __REG32((hw_base) + GIC_RSGI_OFFSET + 0x280U)
#define GIC_RDISTSGI_ISACTIVER0(hw_base) __REG32((hw_base) + GIC_RSGI_OFFSET + 0x300U)
#define GIC_RDISTSGI_ICACTIVER0(hw_base) __REG32((hw_base) + GIC_RSGI_OFFSET + 0x380U)
#define GIC_RDISTSGI_IPRIORITYR(hw_base, n) __REG32((hw_base) + GIC_RSGI_OFFSET + 0x400U + ((n) / 4U) * 4U)
#define GIC_RDISTSGI_ICFGR0(hw_base) __REG32((hw_base) + GIC_RSGI_OFFSET + 0xC00U)
#define GIC_RDISTSGI_ICFGR1(hw_base) __REG32((hw_base) + GIC_RSGI_OFFSET + 0xC04U)
#define GIC_RDISTSGI_IGRPMODR0(hw_base, n) __REG32((hw_base) + GIC_RSGI_OFFSET + 0xD00U + (n)*4)
#define GIC_RDISTSGI_NSACR(hw_base) __REG32((hw_base) + GIC_RSGI_OFFSET + 0xE00U)

#define GIC_RSGI_AFF1_OFFSET 16
#define GIC_RSGI_AFF2_OFFSET 32
#define GIC_RSGI_AFF3_OFFSET 48

   u32 ArmGicCpuMaskToAffval(u32 *cpu_mask, u32 *cluster_id, u32 *target_list);
   u64 GetMainCpuAffval(void);
   int ArmGicGetActiveIrq(u32 index);
   void ArmGicAck(u32 index, int irq);

   void ArmGicMask(u32 index, int irq);
   void ArmGicUmask(u32 index, int irq);

   u32 ArmGicGetPendingIrq(u32 index, int irq);
   void ArmGicSetPendingIrq(u32 index, int irq);
   void ArmGicClearPendingIrq(u32 index, int irq);

   void ArmGicSetConfiguration(u32 index, int irq, uint32_t config);
   u32 ArmGicGetConfiguration(u32 index, int irq);

   void ArmGicClearActive(u32 index, int irq);

   void ArmGicSetCpu(u32 index, int irq, unsigned int cpumask);
   u32 ArmGicGetTargetCpu(u32 index, int irq);

   void ArmGicSetPriority(u32 index, int irq, u32 priority);
   u32 ArmGicGetPriority(u32 index, int irq);

   void ArmGicSetInterfacePriorMask(u32 index, u32 priority);
   u32 ArmGicGetInterfacePriorMask(u32 index);

   void ArmGicSetBinaryPoint(u32 index, u32 binary_point);
   u32 ArmGicGetBinaryPoint(u32 index);

   u32 ArmGicGetIrqStatus(u32 index, int irq);

   void ArmGicSendAffinitySgi(u32 index, int irq, u32 cpu_mask, u32 routing_mode);
   u32 ArmGicGetHighPendingIrq(u32 index);

   u32 ArmGicGetInterfaceId(u32 index);

   void ArmGicSetGroup(u32 index, int irq, u32 group);
   u32 ArmGicGetGroup(u32 index, int irq);

   int ArmGicRedistAddressSet(u32 index, u32 redist_addr, u32 cpu_id);
   int ArmGicCpuInterfaceAddressSet(u32 index, u32 interface_addr, u32 cpu_id);
   int ArmGicDistInit(u32 index, u32 dist_base, int irq_start);
   int ArmGicCpuInit(u32 index);
   int ArmGicRedistInit(u32 index);

   void ArmGicDumpType(u32 index);
   void ArmGicDump(u32 index);

   void ArmGicSetSystemRegisterEnableMask(u32 index, u32 value);
   u32 ArmGicGetSystemRegisterEnableMask(u32 index);
   void ArmGicSecondaryCpuInit(void);

/* for Gic trace */
#include "ft_debug.h"

#define GicV3_DEBUG_TAG "Gicv3"
#define GicV3_ERROR(format, ...) FT_DEBUG_PRINT_E(GicV3_DEBUG_TAG, format, ##__VA_ARGS__)
#define GicV3_DEBUG_I(format, ...) FT_DEBUG_PRINT_I(GicV3_DEBUG_TAG, format, ##__VA_ARGS__)
#define GicV3_DEBUG_D(format, ...) FT_DEBUG_PRINT_D(GicV3_DEBUG_TAG, format, ##__VA_ARGS__)
#define GicV3_DEBUG_W(format, ...) FT_DEBUG_PRINT_W(GicV3_DEBUG_TAG, format, ##__VA_ARGS__)

#ifdef __cplusplus
}
#endif

#endif // !